package com.apes.scm.rcl.service;

import com.apes.framework.util.DateUtil;
import com.apes.framework.util.Tools;
import com.apes.scm.rcl.model.RclInst;
import com.apes.scm.rcl.model.RclTask;
import com.apes.scm.rcl.model.RclTaskInst;
import com.apes.scm.rcl.parser.EsbTask;
import com.apes.scm.rcl.parser.ProcedureTask;
import com.apes.scm.rcl.repository.RclInstRepository;
import com.apes.scm.rcl.repository.RclTaskInstRepository;
import com.apes.scm.rcl.repository.RclTaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Calendar;
import java.util.Date;

/**
 * 功能：日结
 *
 * @author xul
 * @create 2019-12-04 15:05
 */
@Service
public class RclService {

    @Autowired
    private RclInstRepository rclInstRepository;

    @Autowired
    private RclTaskRepository rclTaskRepository;

    @Autowired
    private RclTaskInstRepository rclTaskInstRepository;


    public void process() {
        RclInst currentRclInst = getCurrentRclInst();
        if (currentRclInst == null) return;
        Date startDate = new Date();
        try {
            execute(() -> {
                RclTask rclTask = rclTaskRepository.findOne(currentRclInst.getCurrentTask());
                /**执行日结任务**/
                execute(rclTask, currentRclInst.getTaskDate());

                /**保存日结任务处理实例**/
                saveRclTaskInst(currentRclInst, startDate, true, "success");

                /**保存日结处理实例**/
                currentRclInst.setSuccess(true);
                currentRclInst.setFinish(rclTask.isFinish());
                rclInstRepository.save(currentRclInst);
            });
            /**执行下一个日结任务**/
            process();
        } catch (Exception e) {
            /**日结报错处理**/
            execute(() -> {
                /**保存日结任务处理实例**/
                saveRclTaskInst(currentRclInst, startDate, false, e.getMessage());

                /**更新日结处理实例**/
                currentRclInst.setSuccess(false);
                currentRclInst.setMessage(Tools.getThrowable(e).getMessage());
                rclInstRepository.save(currentRclInst);
            });
        }

    }

    /**
     * 日结执行入口
     *
     * @param rclTask
     */
    private void execute(RclTask rclTask, Date startDate) {
        // 判断是否调用 ESB 或者是调用 存储过程
        String rclTaskType = rclTask.getTaskType().getCode();

        // 判断
        if ("esb".equals(rclTaskType)) {
            EsbTask parser = new EsbTask();
            parser.setEsbId(rclTask.getActuator());
            parser.execute(startDate);
        } else if ("procedure".equals(rclTaskType)) {
            ProcedureTask parser = new ProcedureTask();
            parser.setProcedureName(rclTask.getActuator());
            parser.execute(startDate);
        } else {
            throw new RuntimeException("没有实现日处理逻辑");
        }

    }

    private void saveRclTaskInst(RclInst currentRclInst, Date startDate, boolean success, String message) {
        RclTaskInst rclTaskInst = new RclTaskInst();
        rclTaskInst.setTask(currentRclInst.getCurrentTask());
        rclTaskInst.setTaskDate(currentRclInst.getTaskDate());
        rclTaskInst.setStartDate(startDate);
        rclTaskInst.setEndDate(new Date());
        rclTaskInst.setSuccess(success);
        rclTaskInst.setMessage(message);
        rclTaskInstRepository.save(rclTaskInst);
    }

    private RclInst getCurrentRclInst() {
        RclInst currentRclInst;
        RclInst lastRclInst = rclInstRepository.findFirstByOrderByTaskDateDesc();
        if (lastRclInst == null) throw new RuntimeException("请初始化日结开始日期！");
        if (lastRclInst.isFinish()) {
            Date taskDate = DateUtil.add(lastRclInst.getTaskDate(), Calendar.DATE, 1);
            /**日结计划检查 **/

            if (DateUtil.dateCompare(taskDate, new Date()) >= 0) {
                return null;
            }

            currentRclInst = new RclInst();
            RclTask currentTask = rclTaskRepository.findByStartedIsTrue();
            currentRclInst.setCurrentTask(currentTask.getId());
            currentRclInst.setTaskDate(taskDate);
            return currentRclInst;
        } else {
            currentRclInst = lastRclInst;
            if (currentRclInst.isSuccess()) {
                RclTask currentTask = rclTaskRepository.findByParentId(currentRclInst.getCurrentTask());
                currentRclInst.setCurrentTask(currentTask.getId());
            }
            return currentRclInst;
        }
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void execute(Callback callback) {
        transactionTemplate.execute(status -> {
            try {
                callback.execute();
                return null;
            } catch (Exception e) {
                status.isRollbackOnly();
                throw new RuntimeException(e.getMessage());
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        void execute();
    }

    public void start() {
        System.out.println("----------------------------------日结开始----------------------------------");
    }

    public void end() {
        System.out.println("----------------------------------日结结束----------------------------------");
    }

}
